﻿//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Mvc;
using System.Web;
using System.IO;
using System.Globalization;
using DNA.Mvc.jQuery;

namespace DNA.Mvc.UI
{
    /// <summary>
    /// The helper class which provides the UI Helper methods for the jQuery Mvc Portal
    /// </summary>
    public static class HtmlUIExtensions
    {
        private static WebSiteContext Context
        {
            get
            {
                return DependencyResolver.Current.GetService<WebSiteContext>();
            }
        }

        [Obsolete]
        public static CultureInfo CurrentCultureInfo(this HtmlHelper helper)
        {
            var culture = GetCultureInfo();
            System.Threading.Thread.CurrentThread.CurrentCulture = culture;
            System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
            return culture;
        }

        [Obsolete]
        public static CultureInfo GetCultureInfo()
        {

            string lanName = Context.Web.DefaultLanguage;
            HttpContext context = HttpContext.Current;
            if (context.Request.IsAuthenticated)
            {
                if (context.Profile["Language"] != null)
                {
                    if (!string.IsNullOrEmpty(context.Profile["Language"].ToString()))
                        lanName = context.Profile["Language"].ToString();
                }
            }
            else
            {
                string key = context.Request.AnonymousID;
                if (context.Request.Cookies[key] != null)
                {
                    if (!string.IsNullOrEmpty(context.Request.Cookies[key].Values["Language"].ToString()))
                        lanName = context.Request.Cookies[key].Values["Language"].ToString();
                }
            }

            return GetCultureInfo(lanName);
        }

        public static CultureInfo GetCultureInfo(string name)
        {
            string locName = name;
            if (string.IsNullOrEmpty(locName))
            {
                string defaultLanguage = Context.Web.DefaultLanguage;
                if (!string.IsNullOrEmpty(defaultLanguage))
                    locName = defaultLanguage;
            }
            return new CultureInfo(locName);
        }

        /// <summary>
        /// Render the an ajax mail link tag
        /// </summary>
        /// <param name="helper">The HTML helper</param>
        /// <param name="email">the email address where the link refers to.</param>
        /// <remarks>
        ///  Mail link is a security Method.It will estimate if current user could  use the mail function of the portal.
        ///  when the link click a dialog will open user can send a mail to the specified address.You must enabling the 
        ///  SMTP Service on your server or setting the SMTP correctly.
        /// </remarks>
        /// <returns>HTML Tags</returns>
        public static MvcHtmlString MailTo(this HtmlHelper helper, string email)
        {
            StringBuilder html = new StringBuilder();
            html.Append("<a href=\"mailto:" + email + "\" title=\"Send mail to this user\" style=\"position:relative;\">");
            html.Append("<span class=\"ui-icon ui-icon-mail-closed\" style=\"float: left; margin-right: 0.3em;\" ></span>");
            html.Append(email + "</a>");
            return MvcHtmlString.Create(html.ToString());
        }

        /// <summary>
        /// Render the header elements for portal
        /// </summary>
        /// <returns></returns>
        public static MvcHtmlString Headers(this HtmlHelper helper)
        {
            StringBuilder headers = new StringBuilder();
            var web = Context.Web;

            if (web != null)
            {
                string _title = web.Title + (!string.IsNullOrEmpty(Context.Title) ? (" - " + Context.Title) : "");
                string currentDesc = Context.Description;
                string currentKeywords = Context.Keywords;

                headers.Append("<title>");
                headers.Append(_title);
                headers.AppendLine("</title>");
                headers.AppendLine(helper.Meta("distribution", "global"));
                headers.AppendLine(helper.Meta("generator", "DotNetAge " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()));

                UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);

                if (!string.IsNullOrEmpty(currentDesc))
                    headers.AppendLine(helper.Meta("description", currentDesc));

                if (!string.IsNullOrEmpty(currentKeywords))
                    headers.AppendLine(helper.Meta("keywords", currentKeywords));

                if (!string.IsNullOrEmpty(web.ShortcutIconUrl))
                {
                    headers.AppendLine(Link("shortcut icon", "image/x-icon", web.ShortcutIconUrl))
                                .AppendLine(Link("bookmark", "image/x-icon", web.ShortcutIconUrl));
                }

                string baseUrl = helper.ViewContext.RequestContext.HttpContext.Request.Url.Scheme + "://" + helper.ViewContext.RequestContext.HttpContext.Request.Url.Authority;
                if (!helper.ViewContext.RequestContext.HttpContext.Request.ApplicationPath.Equals("/"))
                    baseUrl += helper.ViewContext.RequestContext.HttpContext.Request.ApplicationPath;

                headers.AppendLine(Link("RSD", "EditURI", "application/rsd+xml", baseUrl + urlHelper.Action("Rsd", "OpenAPI", new { Area = "Publishing" })));
                headers.AppendLine(Link("wlwmanifest", "application/wlwmanifest+xml", baseUrl + urlHelper.Action("WlWManifest", "OpenAPI", new { Area = "Publishing" })));
                headers.AppendLine(Link(web.Title, "search", "application/opensearchdescription+xml", baseUrl + urlHelper.Action("Osd", "Search", new { Area = "" })));
                headers.AppendLine(Link(web.Title, "alternate", "application/rss+xml", baseUrl + "/feeds/" + web.Name + "/rss"));
                headers.AppendLine(Link(web.Title, "alternate", "application/atom+xml", baseUrl + "/feeds/" + web.Name + "/atom"));

                var metaFile = helper.ViewContext.HttpContext.Server.MapPath("~/content/templates/metas.cshtml");
                if (System.IO.File.Exists(metaFile))
                {
                    var content = System.IO.File.ReadAllText(metaFile);
                    if (!string.IsNullOrEmpty(content))
                        headers.AppendLine(content);
                }

                string themeName = "";
                if (!string.IsNullOrEmpty(web.Theme))
                    themeName = web.Theme;

                if (!string.IsNullOrEmpty(web.MasterTools.GoogleWebMasterTools))
                    headers.Append(helper.Meta("google-site-verification", web.MasterTools.GoogleWebMasterTools));

                if (!string.IsNullOrEmpty(web.MasterTools.YahooSiteExplorer))
                    headers.Append(helper.Meta("y_key", web.MasterTools.YahooSiteExplorer));

                if (!string.IsNullOrEmpty(web.MasterTools.BingWebMasterCenter))
                    headers.Append(helper.Meta("msvalidate.01", web.MasterTools.BingWebMasterCenter));


                if (helper.ViewContext.HttpContext.Request.IsAuthenticated)
                {
                    if (helper.ViewContext.HttpContext.Profile["Theme"] != null)
                    {
                        if (!string.IsNullOrEmpty(helper.ViewContext.HttpContext.Profile["Theme"].ToString()))
                            themeName = helper.ViewContext.HttpContext.Profile["Theme"].ToString();
                    }
                }
                string gaScript = helper.GetGoogleAnalyticsCode();
                if (!string.IsNullOrEmpty(gaScript))
                {
                    headers.Append(gaScript)
                    .Append("<script type=\"text/javascript\" src=\"https://apis.google.com/js/plusone.js\"></script>");
                }
                headers.Append(helper.Theme(themeName));

                //generate the style sheet for the header
                if (!string.IsNullOrEmpty(web.CssText))
                {
                    headers.AppendLine("<style type=\"text/css\" id=\"customstyle\">");
                    headers.AppendLine(web.CssText);
                    headers.AppendLine("</style>");
                }

                bool isDesignMode = false;
                string key = "design";
                if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]))
                    bool.TryParse(HttpContext.Current.Request.QueryString[key], out isDesignMode);
                var Url = new UrlHelper(helper.ViewContext.RequestContext);

                if (isDesignMode)
                {
                    var _ajax = new AjaxHelper(helper.ViewContext, helper.ViewDataContainer);
                    _ajax.jQuery("body", "portable", new
                    {
                        mode = key,
                        url = Url.Action("LoadData", "Widget", new { Area = "" }),
                        baseUrl = Url.Content(string.Format("~/{0}-Widget/", web.Name))
                    });
                }

                return MvcHtmlString.Create(headers.ToString());
            }
            return MvcHtmlString.Empty;
        }


        /// <summary>
        /// Render the Theme elements for the portal.
        /// </summary>
        /// <param name="helper">The HTML Helper</param>
        /// <param name="theme">The Theme name which to render.</param>
        /// <returns></returns>
        public static string Theme(this HtmlHelper helper, string theme)
        {
            return Theme(theme);
        }

        public static string Theme(string theme)
        {
            StringBuilder links = new StringBuilder();
            links.AppendLine(CssLinks("~/Content/Themes/" + theme));
            return links.ToString();
        }

        /// <summary>
        /// Render the stylesheet links tag.
        /// </summary>
        /// <remarks>
        /// This helper will find all the *.css file in the specified path and resovle the client url of the files.
        /// </remarks>
        /// <param name="helper">The HTML Helper</param>
        /// <param name="path">The path where contains the stylesheets</param>
        /// <returns></returns>
        public static string CssLinks(this HtmlHelper helper, string path)
        {
            return CssLinks(path);
        }

        public static string CssLinks(string path)
        {
            StringBuilder links = new StringBuilder();
            string filePath = HttpContext.Current.Server.MapPath(path);
            if (Directory.Exists(filePath))
            {
                string[] cssFiles = System.IO.Directory.GetFiles(filePath, "*.css");
                for (int i = 0; i < cssFiles.Length; i++)
                {
                    string cssFile = System.IO.Path.GetFileName(cssFiles[i]);
                    links.AppendLine(CssLink(path + "/" + cssFile));
                }
            }
            return links.ToString();
        }

        /// <summary>
        /// Render the meta tag 
        /// </summary>
        /// <param name="name">The meta name</param>
        /// <param name="content">The meta content</param>
        /// <returns></returns>
        public static string Meta(this HtmlHelper helper, string name, string content)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("<meta");
            builder.Append(" name=\"" + name + "\"");
            builder.Append(" content=\"" + content + "\" />");
            return builder.ToString();
        }

        /// <summary>
        /// enable auto generate google analytics track script 
        /// </summary>
        /// <remarks>
        /// if WebSite.GAAccount is empty this method will not invoke
        /// </remarks>
        /// <returns></returns>
        public static string GetGoogleAnalyticsCode(this HtmlHelper helper)
        {
            //Microsoft.Web.Helpers.Analytics.GetGoogleAsyncHtml
            // var web = WebSite.Open();
            var _account = Context.RootWeb.MasterTools.GAAccount;

            if (!string.IsNullOrEmpty(_account))
            {
                StringBuilder scripts = new StringBuilder();

                scripts.Append("<script type=\"text/javascript\">")
                    .Append("var _gaq = _gaq || [];")
                .Append("_gaq.push(['_setAccount', '")
                .Append(_account)
                .Append("']);")
                .Append("_gaq.push(['_trackPageview']); ")
                .Append("(function(){")
                .Append("var ga = document.createElement('script');")
                .Append("ga.type = 'text/javascript';")
                .Append("ga.async = true; ")
                .Append("ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';")
                .Append("var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);")
                .Append("})();")
                .Append("</script>");
                return scripts.ToString();
                //helper.RegisterStartupScript(scripts.ToString());
            }
            return "";
        }

        /// <summary>
        /// Render the link tag for css stylesheet
        /// </summary>
        /// <param name="helper">The Html Helper</param>
        /// <param name="url">the url of the stylesheet</param>
        /// <returns></returns>
        public static MvcHtmlString CssLink(this HtmlHelper helper, string url)
        {
            return MvcHtmlString.Create(CssLink(url));
        }

        public static string Link(string rel, string type, string href)
        {
            return Link("", rel, type, href);
        }

        public static string Link(string title, string rel, string type, string href)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("<link")
                      .Append(" rel=\"" + rel + "\"")
                      .Append(" type=\"" + type + "\"");
            if (!string.IsNullOrEmpty(title))
                builder.Append(" title=\"" + title + "\"");
            string _url = href;

            if (VirtualPathUtility.IsAppRelative(href))
                _url = VirtualPathUtility.ToAbsolute(href);
            builder.Append(" href=\"" + _url + "\" />");
            return builder.ToString();
        }

        public static string CssLink(string url)
        {
            return Link("stylesheet", "text/css", url);
        }

        //public static MvcHtmlString Scripts(this HtmlHelper heper, params string[] urls)
        //{
        //    StringBuilder strBuilder = new StringBuilder();
        //    for (int i = 0; i < urls.Length; i++)
        //    {
        //        TagBuilder builder = new TagBuilder("script");
        //        builder.Attributes.Add("type", "text/javascript");
        //        builder.Attributes.Add("src", urls[i]);
        //        strBuilder.AppendLine(builder.ToString());
        //    }
        //    return MvcHtmlString.Create(strBuilder.ToString());
        //}

        /// <summary>
        /// Build the script reference link element 
        /// </summary>
        /// <remarks>
        ///  This method will append the "~/Scripts/" to the script link url.
        /// </remarks>
        /// <param name="urls">the script url reference params list</param>
        /// <returns></returns>
        public static MvcHtmlString ScriptRefs(this HtmlHelper helper, bool isInternal, params string[] urls)
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < urls.Length; i++)
                builder.AppendLine(ScriptRef(helper, urls[i], isInternal));
            return MvcHtmlString.Create(builder.ToString());
        }

        public static MvcHtmlString ScriptRefs(this HtmlHelper helper, params string[] urls)
        {
            return helper.ScriptRefs(true, urls);
        }

        /// <summary>
        /// Build the script reference link element 
        /// </summary>
        /// <remarks>This method will append the "~/Scripts/" to the script link url.</remarks>
        /// <param name="helper">The html helper object to extends.</param>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string ScriptRef(this HtmlHelper helper, string url, bool isInternal = true)
        {
            string _url = url;
            TagBuilder builder = new TagBuilder("script");
            builder.Attributes.Add("type", "text/javascript");

            if (isInternal)
            {
                if (!_url.StartsWith("~/Scripts/"))
                    _url = "~/Scripts/" + url;
            }

            if (VirtualPathUtility.IsAppRelative(_url))
                _url = VirtualPathUtility.ToAbsolute(_url);
            builder.Attributes.Add("src", _url);

            //Check if the script is already register.
            if (ScriptIsRegistered(helper, _url))
                return "";

            return builder.ToString();
        }

        public static bool ScriptIsRegistered(HtmlHelper helper, string _url)
        {
            List<string> srl = null;
            if (helper.ViewContext.TempData["ScriptRegisterList"] == null)
            {
                srl = new List<string>();
                helper.ViewContext.TempData["ScriptRegisterList"] = srl;
                return false;
            }

            srl = (List<string>)helper.ViewContext.TempData["ScriptRegisterList"];
            return srl.Contains(_url);
        }

        public static MvcHtmlString Avatar(this HtmlHelper helper, string userName)
        {
            TagBuilder link = new TagBuilder("a");
            link.AddCssClass("ui-widget-content ui-state-default");
            link.Attributes.Add("style", "padding:3px;");
            link.Attributes.Add("href", ((new UrlHelper(helper.ViewContext.RequestContext)).Action("Info", "Account", new { Area = "", userName = userName })));
            var p = System.Web.Profile.ProfileBase.Create(userName);
            link.InnerHtml = helper.Image(p.GetPropertyValue("Avatar").ToString(), 60, 60).ToString();
            return MvcHtmlString.Create(link.ToString());
        }

        public static MvcHtmlString UserLink(this HtmlHelper helper, string userName)
        {
            return helper.UserLink("", userName);
        }

        public static MvcHtmlString UserLink(this HtmlHelper helper, string userName, object htmlAttributes)
        {
            return helper.UserLink("", userName, htmlAttributes);
        }

        public static MvcHtmlString UserLink(this HtmlHelper helper, string iconClass, string userName)
        {
            return helper.UserLink(iconClass, userName, null);
        }

        public static MvcHtmlString UserLink(this HtmlHelper helper, string iconClass, string userName, object htmlAttributes)
        {
            TagBuilder link = new TagBuilder("a");
            var user = System.Web.Security.Membership.GetUser(userName);
            if (user != null)
            {
                link.MergeAttribute("href", user.GetPermalinkUrl().ToString());
                link.AddCssClass("d-user");
            }
            //link.Attributes.Add("href", ((new UrlHelper(helper.ViewContext.RequestContext)).Action("Info", "Account", new { Area = "", userName = userName })));
            //link.MergeAttribute("href",
            if (!string.IsNullOrEmpty(iconClass))
            {
                TagBuilder span = new TagBuilder("span");
                span.AddCssClass(iconClass);
                span.Attributes.Add("style", "float:left");
                link.InnerHtml = span.ToString() + ((user != null) ? ((string.IsNullOrEmpty(user.GetProfile().DisplayName) ? userName : user.GetProfile().DisplayName)) : userName);
            }
            else
                link.InnerHtml = user != null ? (string.IsNullOrEmpty(user.GetProfile().DisplayName) ? userName : user.GetProfile().DisplayName) : userName;

            if (htmlAttributes != null)
                link.MergeAttributes<string, object>(ObjectHelper.ConvertObjectToDictionary(htmlAttributes));
            return MvcHtmlString.Create(link.ToString());
        }

        /// <summary>
        /// Enable the client validation for jQuery
        /// </summary>
        /// <param name="helper"></param>
        [Obsolete("This method is not use anymore", true)]
        public static void EnableClientjQueryValidation(this HtmlHelper helper)
        {
            helper.EnableClientValidation();
            helper.RegisterStartupScript("EnableClientValidation(mvcClientValidationMetadata[0]);");
        }

        public static MvcHtmlString Logo(this HtmlHelper helper)
        {
            return Logo(helper, null);
        }

        /// <summary>
        /// Render the logo image link of the portal
        /// </summary>
        /// <param name="helper">The Html Helper</param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static MvcHtmlString Logo(this HtmlHelper helper, object htmlAttributes)
        {
            var web = Context.Web;
            // WebSite.Open(helper.ViewContext.RouteData);
            if (web == null)
                web = Context.RootWeb;
            // WebSite.Open();

            if (!string.IsNullOrEmpty(web.LogoImageUrl))
            {
                TagBuilder builder = new TagBuilder("img");

                if (htmlAttributes != null)
                    builder.MergeAttributes<string, object>(ObjectHelper.ConvertObjectToDictionary(htmlAttributes));
                builder.Attributes.Add("alt", web.Description);
                builder.Attributes.Add("src", (new UrlHelper(helper.ViewContext.RequestContext)).Content(web.LogoImageUrl));
                builder.AddCssClass("dna-logo");
                return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
            }
            return MvcHtmlString.Empty;
        }

        /// <summary>
        /// Render the copyright information of the portal.
        /// </summary>
        /// <param name="helper">The Html helper</param>
        /// <returns></returns>
        public static MvcHtmlString Copyright(this HtmlHelper helper)
        {
            return Copyright(helper, null);
        }

        public static MvcHtmlString Copyright(this HtmlHelper helper, object htmlAttributes)
        {
            var web = Context.Web;
            if (web == null)
                web = Context.RootWeb;

            if (web != null)
            {
                TagBuilder builder = new TagBuilder("div");
                if (htmlAttributes != null)
                    builder.MergeAttributes<string, object>(ObjectHelper.ConvertObjectToDictionary(htmlAttributes));
                builder.SetInnerText(GE.GetContent(web.Copyright));
                builder.InnerHtml += "<div style=\"text-align:center;padding:10px;\">Copyright © 2011 DotNetAge. All rights reserved.Power by <a href=\"http://www.dotnetage.com\" rel=\"follow\" title=\"Click to visit DotNetAge offical site.\">DotNetAge</a> v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() + "</div>";
                return MvcHtmlString.Create(builder.ToString());
            }
            else
                return MvcHtmlString.Empty;
        }

        /// <summary>
        /// Cut the input text
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="text"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static string Cut(this HtmlHelper helper, string text, int len)
        {
            if (string.IsNullOrEmpty(text))
                return text;
            if ((len > 0) && (text.Length > len))
                return text.Substring(0, len) + "...";
            else
                return text;
        }

        public static string ResolveUrl(string url)
        {
            string _url = url;
            if (VirtualPathUtility.IsAppRelative(_url))
                _url = VirtualPathUtility.ToAbsolute(_url);
            return _url;
        }

        public static string ScriptBlock(this HtmlHelper helper, string script)
        {
            StringBuilder scripts = new StringBuilder();
            scripts.AppendLine("<script type='text/javascript'>");
            scripts.Append(script);
            //scripts.AppendLine("});");
            scripts.AppendLine("</script>");
            return scripts.ToString();
        }

        public static MvcHtmlString StartupScripts(this HtmlHelper helper)
        {
            StringBuilder resScripts = new StringBuilder();
            if (helper.ViewContext.TempData["ClientRes"] != null)
            {
                IDictionary<string, string> resources = helper.ViewContext.TempData["ClientRes"] as IDictionary<string, string>;
                if (resources != null)
                {

                    List<string> options = new List<string>();

                    foreach (string key in resources.Keys)
                        options.Add(key + ":'" + resources[key] + "'");

                    resScripts.Append("$.extend(portal.res,")
                                .Append("{" + string.Join(",", options.ToArray()) + "}")
                                .Append(");");
                    helper.ViewContext.TempData.Remove("ClientRes");
                }
            }

            if (helper.ViewContext.TempData["StartupScripts"] != null)
            {
                StringBuilder scripts = new StringBuilder();
                scripts.AppendLine("<script type='text/javascript'>");
                scripts.AppendLine("$(function(){");
                if (resScripts.Length > 0)
                    scripts.Append(resScripts.ToString());
                scripts.Append(helper.ViewContext.TempData["StartupScripts"].ToString());
                scripts.AppendLine("});");
                scripts.AppendLine("</script>");
                helper.ViewContext.TempData.Remove("StartupScripts");
                return MvcHtmlString.Create(scripts.ToString());
            }
            return MvcHtmlString.Empty;
        }

        /// <summary>
        /// Register the startup script to the context then using StartupScripts method the render all registed scripts.
        /// </summary>
        /// <param name="helper">The helper object</param>
        /// <param name="script">The script to register</param>
        /// <remarks>
        /// This method will wrapp the try{}catch(){} block of the specified script.
        /// </remarks>
        public static void RegisterStartupScript(this HtmlHelper helper, string script)
        {
            //string securityScript = "try{" + script + "}catch(e){uiHelper.showMsg('Client script error',e);}";
            string securityScript = script;// "try{" + script + "}catch(e){alert(e.description );}";
            if (helper.ViewContext.TempData["StartupScripts"] != null)
                helper.ViewContext.TempData["StartupScripts"] += "\r\n" + securityScript;
            else
                helper.ViewContext.TempData["StartupScripts"] = securityScript;
        }

        public static HtmlElementFactory Dna(this HtmlHelper helper)
        {
            return new HtmlElementFactory(helper);
        }
    }
}
